﻿using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace HslCommunication.Profinet.Siemens
{
	/// <summary>
	/// Contains the methods to convert between <see cref="T:System.DateTime" /> and S7 representation of datetime values.
	/// </summary>
	/// <remarks>
	/// 这部分的代码参考了另一个s7的库，感谢原作者，此处贴出出处，遵循 MIT 协议
	///
	/// https://github.com/S7NetPlus/s7netplus
	/// </remarks>
	// Token: 0x02000048 RID: 72
	public class SiemensDateTime
	{
		/// <summary>
		/// Parses a <see cref="T:System.DateTime" /> value from bytes.
		/// </summary>
		/// <param name="bytes">Input bytes read from PLC.</param>
		/// <returns>A <see cref="T:System.DateTime" /> object representing the value read from PLC.</returns>
		/// <exception cref="T:System.ArgumentOutOfRangeException">Thrown when the length of
		///   <paramref name="bytes" /> is not 8 or any value in <paramref name="bytes" />
		///   is outside the valid range of values.</exception>
		// Token: 0x060005F2 RID: 1522 RVA: 0x0001B378 File Offset: 0x00019578
		public static DateTime FromByteArray(byte[] bytes)
		{
			return SiemensDateTime.FromByteArrayImpl(bytes);
		}

		/// <summary>
		/// Parses an array of <see cref="T:System.DateTime" /> values from bytes.
		/// </summary>
		/// <param name="bytes">Input bytes read from PLC.</param>
		/// <returns>An array of <see cref="T:System.DateTime" /> objects representing the values read from PLC.</returns>
		/// <exception cref="T:System.ArgumentOutOfRangeException">Thrown when the length of
		///   <paramref name="bytes" /> is not a multiple of 8 or any value in
		///   <paramref name="bytes" /> is outside the valid range of values.</exception>
		// Token: 0x060005F3 RID: 1523 RVA: 0x0001B390 File Offset: 0x00019590
		public static DateTime[] ToArray(byte[] bytes)
		{
			bool flag = bytes.Length % 8 != 0;
			if (flag)
			{
				throw new ArgumentOutOfRangeException("bytes", bytes.Length, string.Format("Parsing an array of DateTime requires a multiple of 8 bytes of input data, input data is '{0}' long.", bytes.Length));
			}
			int num = bytes.Length / 8;
			DateTime[] array = new DateTime[bytes.Length / 8];
			for (int i = 0; i < num; i++)
			{
				array[i] = SiemensDateTime.FromByteArrayImpl(new ArraySegment<byte>(bytes, i * 8, 8).Array);
			}
			return array;
		}

		// Token: 0x060005F4 RID: 1524 RVA: 0x0001B418 File Offset: 0x00019618
		private static DateTime FromByteArrayImpl(IList<byte> bytes)
		{
			bool flag = bytes.Count != 8;
			if (flag)
			{
				throw new ArgumentOutOfRangeException("bytes", bytes.Count, string.Format("Parsing a DateTime requires exactly 8 bytes of input data, input data is {0} bytes long.", bytes.Count));
			}
			int year = SiemensDateTime.<FromByteArrayImpl>g__ByteToYear|4_1(bytes[0]);
			int month = SiemensDateTime.<FromByteArrayImpl>g__AssertRangeInclusive|4_2(SiemensDateTime.<FromByteArrayImpl>g__DecodeBcd|4_0(bytes[1]), 1, 12, "month");
			int day = SiemensDateTime.<FromByteArrayImpl>g__AssertRangeInclusive|4_2(SiemensDateTime.<FromByteArrayImpl>g__DecodeBcd|4_0(bytes[2]), 1, 31, "day of month");
			int hour = SiemensDateTime.<FromByteArrayImpl>g__AssertRangeInclusive|4_2(SiemensDateTime.<FromByteArrayImpl>g__DecodeBcd|4_0(bytes[3]), 0, 23, "hour");
			int minute = SiemensDateTime.<FromByteArrayImpl>g__AssertRangeInclusive|4_2(SiemensDateTime.<FromByteArrayImpl>g__DecodeBcd|4_0(bytes[4]), 0, 59, "minute");
			int second = SiemensDateTime.<FromByteArrayImpl>g__AssertRangeInclusive|4_2(SiemensDateTime.<FromByteArrayImpl>g__DecodeBcd|4_0(bytes[5]), 0, 59, "second");
			int num = SiemensDateTime.<FromByteArrayImpl>g__AssertRangeInclusive|4_2(SiemensDateTime.<FromByteArrayImpl>g__DecodeBcd|4_0(bytes[6]), 0, 99, "first two millisecond digits");
			int num2 = SiemensDateTime.<FromByteArrayImpl>g__AssertRangeInclusive|4_2(bytes[7] >> 4, 0, 9, "third millisecond digit");
			int num3 = SiemensDateTime.<FromByteArrayImpl>g__AssertRangeInclusive|4_2((int)(bytes[7] & 15), 1, 7, "day of week");
			return new DateTime(year, month, day, hour, minute, second, num * 10 + num2);
		}

		/// <summary>
		/// Converts a <see cref="T:System.DateTime" /> value to a byte array.
		/// </summary>
		/// <param name="dateTime">The DateTime value to convert.</param>
		/// <returns>A byte array containing the S7 date time representation of <paramref name="dateTime" />.</returns>
		/// <exception cref="T:System.ArgumentOutOfRangeException">Thrown when the value of
		///   <paramref name="dateTime" /> is before <see cref="P:SpecMinimumDateTime" />
		///   or after <see cref="P:SpecMaximumDateTime" />.</exception>
		// Token: 0x060005F5 RID: 1525 RVA: 0x0001B560 File Offset: 0x00019760
		public static byte[] ToByteArray(DateTime dateTime)
		{
			bool flag = dateTime < SiemensDateTime.SpecMinimumDateTime;
			if (flag)
			{
				throw new ArgumentOutOfRangeException("dateTime", dateTime, string.Format("Date time '{0}' is before the minimum '{1}' supported in S7 date time representation.", dateTime, SiemensDateTime.SpecMinimumDateTime));
			}
			bool flag2 = dateTime > SiemensDateTime.SpecMaximumDateTime;
			if (flag2)
			{
				throw new ArgumentOutOfRangeException("dateTime", dateTime, string.Format("Date time '{0}' is after the maximum '{1}' supported in S7 date time representation.", dateTime, SiemensDateTime.SpecMaximumDateTime));
			}
			return new byte[]
			{
				SiemensDateTime.<ToByteArray>g__EncodeBcd|5_0((int)SiemensDateTime.<ToByteArray>g__MapYear|5_1(dateTime.Year)),
				SiemensDateTime.<ToByteArray>g__EncodeBcd|5_0(dateTime.Month),
				SiemensDateTime.<ToByteArray>g__EncodeBcd|5_0(dateTime.Day),
				SiemensDateTime.<ToByteArray>g__EncodeBcd|5_0(dateTime.Hour),
				SiemensDateTime.<ToByteArray>g__EncodeBcd|5_0(dateTime.Minute),
				SiemensDateTime.<ToByteArray>g__EncodeBcd|5_0(dateTime.Second),
				SiemensDateTime.<ToByteArray>g__EncodeBcd|5_0(dateTime.Millisecond / 10),
				(byte)(dateTime.Millisecond % 10 << 4 | SiemensDateTime.<ToByteArray>g__DayOfWeekToInt|5_2(dateTime.DayOfWeek))
			};
		}

		/// <summary>
		/// Converts an array of <see cref="T:System.DateTime" /> values to a byte array.
		/// </summary>
		/// <param name="dateTimes">The DateTime values to convert.</param>
		/// <returns>A byte array containing the S7 date time representations of <paramref name="dateTimes" />.</returns>
		/// <exception cref="T:System.ArgumentOutOfRangeException">Thrown when any value of
		///   <paramref name="dateTimes" /> is before <see cref="P:SpecMinimumDateTime" />
		///   or after <see cref="P:SpecMaximumDateTime" />.</exception>
		// Token: 0x060005F6 RID: 1526 RVA: 0x0001B680 File Offset: 0x00019880
		public static byte[] ToByteArray(DateTime[] dateTimes)
		{
			List<byte> list = new List<byte>(dateTimes.Length * 8);
			foreach (DateTime dateTime in dateTimes)
			{
				list.AddRange(SiemensDateTime.ToByteArray(dateTime));
			}
			return list.ToArray();
		}

		// Token: 0x060005F9 RID: 1529 RVA: 0x0001B6FC File Offset: 0x000198FC
		[CompilerGenerated]
		internal static int <FromByteArrayImpl>g__DecodeBcd|4_0(byte input)
		{
			return 10 * (input >> 4) + (int)(input & 15);
		}

		// Token: 0x060005FA RID: 1530 RVA: 0x0001B70C File Offset: 0x0001990C
		[CompilerGenerated]
		internal static int <FromByteArrayImpl>g__ByteToYear|4_1(byte bcdYear)
		{
			int num = SiemensDateTime.<FromByteArrayImpl>g__DecodeBcd|4_0(bcdYear);
			bool flag = num < 90;
			int result;
			if (flag)
			{
				result = num + 2000;
			}
			else
			{
				bool flag2 = num < 100;
				if (!flag2)
				{
					throw new ArgumentOutOfRangeException("bcdYear", bcdYear, string.Format("Value '{0}' is higher than the maximum '99' of S7 date and time representation.", num));
				}
				result = num + 1900;
			}
			return result;
		}

		// Token: 0x060005FB RID: 1531 RVA: 0x0001B76C File Offset: 0x0001996C
		[CompilerGenerated]
		internal static int <FromByteArrayImpl>g__AssertRangeInclusive|4_2(int input, byte min, byte max, string field)
		{
			bool flag = input < (int)min;
			if (flag)
			{
				throw new ArgumentOutOfRangeException("input", input, string.Format("Value '{0}' is lower than the minimum '{1}' allowed for {2}.", input, min, field));
			}
			bool flag2 = input > (int)max;
			if (flag2)
			{
				throw new ArgumentOutOfRangeException("input", input, string.Format("Value '{0}' is higher than the maximum '{1}' allowed for {2}.", input, max, field));
			}
			return input;
		}

		// Token: 0x060005FC RID: 1532 RVA: 0x0001B7E0 File Offset: 0x000199E0
		[CompilerGenerated]
		internal static byte <ToByteArray>g__EncodeBcd|5_0(int value)
		{
			return (byte)(value / 10 << 4 | value % 10);
		}

		// Token: 0x060005FD RID: 1533 RVA: 0x0001B7FE File Offset: 0x000199FE
		[CompilerGenerated]
		internal static byte <ToByteArray>g__MapYear|5_1(int year)
		{
			return (byte)((year < 2000) ? (year - 1900) : (year - 2000));
		}

		// Token: 0x060005FE RID: 1534 RVA: 0x0001B819 File Offset: 0x00019A19
		[CompilerGenerated]
		internal static int <ToByteArray>g__DayOfWeekToInt|5_2(DayOfWeek dayOfWeek)
		{
			return (int)(dayOfWeek + 1);
		}

		/// <summary>
		/// The minimum <see cref="T:System.DateTime" /> value supported by the specification.
		/// </summary>
		// Token: 0x04000193 RID: 403
		public static readonly DateTime SpecMinimumDateTime = new DateTime(1990, 1, 1);

		/// <summary>
		/// The maximum <see cref="T:System.DateTime" /> value supported by the specification.
		/// </summary>
		// Token: 0x04000194 RID: 404
		public static readonly DateTime SpecMaximumDateTime = new DateTime(2089, 12, 31, 23, 59, 59, 999);
	}
}
